#include "VStdAfx.h"
#include "VEngine.h"
#include "KMTRender.h"
#include "KMaterialManager.h"
#include "KScene.h"
#include "KWorld.h"
#include "KResourceManager.h"

BOOL KEnginePrivate::RequestShutdown = FALSE;
UINT KEnginePrivate::NumCore = 4;

VEngineEnv VEnv;

VEngine::VEngine(void)
{
	m_MaxFrameRate = 30.0f;
	m_UseFixedTimeStep = FALSE;
	m_FixedTimeStep = -1.0f;
}

VEngine::~VEngine(void)
{
}

void TestEngine()
{


	VMatrix Mat;

	Mat.SetRotateZ(VDEG_RAD(30.0f));





}

extern void InitEngineNames();
extern void InitMaterialNames();
BOOL VEngine::InitEngine(VApplication* App)
{
	if (!VCoreInit())
	{
		return FALSE;
	}
	// init names.
	InitEngineNames();
	InitMaterialNames();
	if (!VRTTClass::InitRTTClasses())
	{
		return FALSE;
	}

	TestEngine();


	VASSERT(VEnv.Engine == NULL);
	if (VEnv.Engine)
	{
		return TRUE;
	}
	VEnv.Engine = this;
	VEnv.App = App;


	g_ResourceManager = VNew KResourceManager;
	if (!g_ResourceManager->Init())
	{
		VDelete g_ResourceManager;
		return FALSE;
	}
	// Init Render.
	{
		VRender* Render = VNew KRenderMT;
		if (!Render->Init())
		{
			delete Render;
			return FALSE;
		}
		VEnv.Render = Render;
	}

	VEnv.MaterialLib = new KMaterialManager;
	if (!KMtlLib->PreInit())
	{
		return FALSE;
	}

	KWorld* World = VNew KWorld;

	if (!World->Init())
	{
		World->Shutdown();
		VDelete World;
		return FALSE;
	}
	VEnv.World = World;

	return TRUE;
}

void VEngine::ShutdownEngine()
{

	if (VEnv.World)
	{
		KWorld* World = (KWorld*)VEnv.World;
		World->Shutdown();
		VDelete World;
		VEnv.World = NULL;
	}

	if (VEnv.Render)
	{

		VEnv.Render->Shutdown();

		


		delete VEnv.Render;
		VEnv.Render = NULL;
	}

	VEnv.Engine = NULL;

	if (g_ResourceManager)
	{
		g_ResourceManager->Shutdown();
		VDelete g_ResourceManager;
		g_ResourceManager = NULL;
	}

	VRTTClass::ShutdownRTTClasses();

	VCoreShutdown();
}

BOOL VEngine::PostInit()
{
	g_Render->PostInitRenderSystem();
	if(!KMtlLib->PostInit())
	{
		return FALSE;
	}

	return TRUE;
}


void VEngine::SetFixedTimeStep(float TimeStep)
{
	m_FixedTimeStep = TimeStep;
	if (m_FixedTimeStep < 0.0001f)
	{
		m_UseFixedTimeStep = FALSE;
	}else
	{
		m_UseFixedTimeStep = TRUE;
	}
}

void VEngine::UpdateFrameTimer()
{
	static float LastTime = 0.0f;
	
	if (m_UseFixedTimeStep)
	{
		VEnv.FrameDeltaTime = m_FixedTimeStep;
		LastTime = VEnv.FrameCurrTime;
		VEnv.FrameCurrTime += VEnv.FrameDeltaTime;
	}else
	{
		VEnv.FrameCurrTime = (float)VGetTime();

		VEnv.FrameDeltaTime = VEnv.FrameCurrTime - LastTime;

		if (VEnv.FrameDeltaTime < 0.0f)
		{
			VEnv.FrameDeltaTime = 0.0f;
		}


		float WaitTime = 0.0f;
		if (m_MaxFrameRate > 0.0f)
		{
			WaitTime =  VMax(1.0f/m_MaxFrameRate - VEnv.FrameDeltaTime, 0.0f);
		}


		UINT IdleStartTick = VGetCycles();
		if (WaitTime > 0.000001f)
		{
			float WaitEndTime = VEnv.FrameCurrTime + WaitTime;

			VSleep(WaitTime * 1000.0f);
		}

		VEnv.FrameCurrTime = (float)VGetTime();
		VEnv.FrameDeltaTime = VEnv.FrameCurrTime - LastTime;
		LastTime = VEnv.FrameCurrTime;
	}
}

void VEngine::UpdateEngine()
{
	/*while(!KEnginePrivate::RequestShutdown)
	{

	Sleep(10);
	}*/

	UpdateFrameTimer();



	ENQUEUE_UNIQUE_RENDER_COMMAND(ResetDeferredUpdatesAndTickTickables,
	{
		//FDeferredUpdateResource::ResetNeedsUpdate();

		// make sure that rendering thread tickables get a change to tick, even if the game thread
		// is keeping the rendering queue always full
		//TickRenderingTickables();
		g_Render->RT_UpdateTickables();
	});

	// Tick Game
	VEnv.App->Update(VEnv.FrameDeltaTime);

	// Update Game

	VEnv.World->Update(VEnv.FrameDeltaTime);

	// Flush.



	// Render.
	DoRender();

	// if device lost .
	g_Render->MT_CheckDeviceLost();


	g_Render->MT_Update();

	g_Render->SyncWithMainThread();

	g_Render->MT_ReleaseRenderRefObject();
}

void VEngine::RequestShutdown()
{
	KEnginePrivate::RequestShutdown = TRUE;
}

VScene* VEngine::CreateScene()
{
	return VNew KScene;
}

void VEngine::DoRender()
{
	VEnv.App->DoRender();
}

